<!DOCTYPE html>
<html>
<head>
    <title>Coupled Oscillator Diagram</title>
    <style>
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0;
        }
        canvas {
            border: 1px solid #ccc;
        }
    </style>
</head>
<body>
    <canvas id="physicsCanvas" width="600" height="400"></canvas>
    <script>
        const canvas = document.getElementById('physicsCanvas');
        const ctx = canvas.getContext('2d');

        // Style settings
        ctx.strokeStyle = 'black';
        ctx.fillStyle = 'black';
        ctx.lineWidth = 2;
        ctx.font = "italic 24px 'Times New Roman'";
        ctx.textAlign = 'center';

        // Helper function to draw a label with a subscript
        function drawSubscript(ctx, char, sub, x, y) {
            ctx.font = "italic 24px 'Times New Roman'";
            const charWidth = ctx.measureText(char).width;
            ctx.fillText(char, x - charWidth / 2, y);
            
            ctx.font = "italic 18px 'Times New Roman'";
            ctx.fillText(sub, x + charWidth / 2 + 1, y + 5);
        }

        // Helper function to draw the spring
        function drawSpring(ctx, x1, y, x2, coils, amplitude) {
            ctx.beginPath();
            const length = x2 - x1;
            const straightPart = 10;
            const coilLength = length - 2 * straightPart;
            const segmentWidth = coilLength / coils;

            let currentX = x1;
            ctx.moveTo(currentX, y);

            // Start straight part
            currentX += straightPart;
            ctx.lineTo(currentX, y);

            // Coils using quadratic curves for a smooth look
            for (let i = 0; i < coils; i++) {
                ctx.quadraticCurveTo(currentX + segmentWidth / 4, y - amplitude, currentX + segmentWidth / 2, y);
                ctx.quadraticCurveTo(currentX + 3 * segmentWidth / 4, y + amplitude, currentX + segmentWidth, y);
                currentX += segmentWidth;
            }

            // End straight part
            ctx.lineTo(x2, y);
            ctx.stroke();
        }

        // --- Main Drawing ---

        // Define coordinates and dimensions
        const yAxis = 250;
        const blockWidth = 80;
        const blockHeight = 80;
        const springLength = 180;
        const centerX = canvas.width / 2;

        // Block 1 (m1)
        const m1_x = centerX - springLength / 2 - blockWidth;
        const m1_y = yAxis - blockHeight;
        ctx.strokeRect(m1_x, m1_y, blockWidth, blockHeight);
        drawSubscript(ctx, 'm', '1', m1_x + blockWidth / 2, m1_y - 15);

        // Block 2 (m2)
        const m2_x = centerX + springLength / 2;
        const m2_y = yAxis - blockHeight;
        ctx.strokeRect(m2_x, m2_y, blockWidth, blockHeight);
        drawSubscript(ctx, 'm', '2', m2_x + blockWidth / 2, m2_y - 15);

        // Spring
        const spring_y = yAxis - blockHeight / 2;
        const spring_x1 = m1_x + blockWidth;
        const spring_x2 = m2_x;
        drawSpring(ctx, spring_x1, spring_y, spring_x2, 4, 15);
        ctx.font = "italic 24px 'Times New Roman'";
        ctx.fillText('k', centerX, spring_y - 25);
        
        // Horizontal Axis
        const axis_start_x = 50;
        const axis_end_x = 550;
        ctx.beginPath();
        ctx.moveTo(axis_start_x, yAxis);
        ctx.lineTo(axis_end_x, yAxis);
        ctx.stroke();

        // Arrowhead for x-axis
        ctx.beginPath();
        ctx.moveTo(axis_end_x, yAxis);
        ctx.lineTo(axis_end_x - 10, yAxis - 5);
        ctx.moveTo(axis_end_x, yAxis);
        ctx.lineTo(axis_end_x - 10, yAxis + 5);
        ctx.stroke();
        ctx.fillText('x', axis_end_x + 15, yAxis + 8);
        
        // Ticks and labels on the axis
        const tickHeight = 5;
        const label_y = yAxis + 25;

        // Tick for x1
        const x1_pos = m1_x + blockWidth / 2;
        ctx.beginPath();
        ctx.moveTo(x1_pos, yAxis - tickHeight);
        ctx.lineTo(x1_pos, yAxis + tickHeight);
        ctx.stroke();
        drawSubscript(ctx, 'x', '1', x1_pos, label_y);

        // Tick for O
        const O_pos = centerX;
        ctx.beginPath();
        ctx.moveTo(O_pos, yAxis - tickHeight);
        ctx.lineTo(O_pos, yAxis + tickHeight);
        ctx.stroke();
        ctx.font = "italic 24px 'Times New Roman'";
        ctx.fillText('O', O_pos, label_y);

        // Tick for x2
        const x2_pos = m2_x + blockWidth / 2;
        ctx.beginPath();
        ctx.moveTo(x2_pos, yAxis - tickHeight);
        ctx.lineTo(x2_pos, yAxis + tickHeight);
        ctx.stroke();
        drawSubscript(ctx, 'x', '2', x2_pos, label_y);

        // Caption
        ctx.font = "22px 'SimSun'"; // A common Chinese font
        ctx.fillText("力图 7.19.1", centerX, canvas.height - 30);

    </script>
</body>
</html>